<!DOCTYPE html><html lang="zh-CN"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="theme-color" content="#0078E7"><meta name="author" content="爱肖彤真是太好了"><meta name="copyright" content="爱肖彤真是太好了"><meta name="generator" content="Hexo 5.1.1"><meta name="theme" content="hexo-theme-yun"><title>python实现分布式锁 | 工藤旧二の博客</title><link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Noto+Serif+SC:wght@900&amp;display=swap" media="none" onload="this.media='all'"><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/star-markdown-css@0.1.19/dist/yun/yun-markdown.min.css"><script src="//at.alicdn.com/t/font_1140697_stqaphw3j4.js" async></script><script src="https://cdn.jsdelivr.net/npm/scrollreveal/dist/scrollreveal.min.js" defer></script><script>document.addEventListener("DOMContentLoaded", () => {
  [".post-card",".post-content img"].forEach((target)=> {
    ScrollReveal().reveal(target);
  })
});
</script><link rel="shortcut icon" type="image/svg+xml" href="/task/yun.ico"><link rel="mask-icon" href="/task/yun.ico" color="#0078E7"><link rel="alternate icon" href="/yun.ico"><link rel="preload" href="/task/css/hexo-theme-yun.css" as="style"><link rel="preload" href="/task/js/utils.js" as="script"><link rel="preload" href="/task/js/hexo-theme-yun.js" as="script"><link rel="prefetch" href="/task/js/sidebar.js" as="script"><link rel="preconnect" href="https://cdn.jsdelivr.net" crossorigin><link rel="stylesheet" href="/task/css/hexo-theme-yun.css"><link rel="alternate" href="/task/atom.xml" title="工藤旧二の博客" type="application/atom+xml"><script id="yun-config">
    const Yun = window.Yun || {};
    window.CONFIG = {"root":"/task/","title":"工藤旧二の博客","version":"0.9.7","anonymous_image":"https://cdn.jsdelivr.net/gh/YunYouJun/cdn/img/avatar/none.jpg","say":{"api":"https://v1.hitokoto.cn","hitokoto":true},"local_search":{"path":"/task/search.xml"},"fireworks":{"colors":["102, 167, 221","62, 131, 225","33, 78, 194"]}};
  </script><script>(function(){
  var bp = document.createElement('script');
  var curProtocol = window.location.protocol.split(':')[0];
  if (curProtocol === 'https') {
    bp.src = 'https://zz.bdstatic.com/linksubmit/push.js';
  }
  else {
    bp.src = 'http://push.zhanzhang.baidu.com/push.js';
  }
  var s = document.getElementsByTagName("script")[0];
  s.parentNode.insertBefore(bp, s);
})();</script><meta name="description" content="分布式锁加锁操作非原子性import threading, time, redis from redis import StrictRedis # 方式一：加锁操作非原子性 # 失败案例  class RedisLock(object):     def __init__(self, redis_conn):         self.redis_conn &#x3D; redis_conn      de">
<meta property="og:type" content="article">
<meta property="og:title" content="python实现分布式锁">
<meta property="og:url" content="http://huang_zhao.gitee.io/task/2021/07/02/python/%E5%AD%A6%E4%B9%A0/%E5%88%86%E5%B8%83%E5%BC%8F%E9%94%81/index.html">
<meta property="og:site_name" content="工藤旧二の博客">
<meta property="og:description" content="分布式锁加锁操作非原子性import threading, time, redis from redis import StrictRedis # 方式一：加锁操作非原子性 # 失败案例  class RedisLock(object):     def __init__(self, redis_conn):         self.redis_conn &#x3D; redis_conn      de">
<meta property="og:locale" content="zh_CN">
<meta property="article:published_time" content="2021-07-02T05:33:43.000Z">
<meta property="article:modified_time" content="2021-07-01T06:13:58.000Z">
<meta property="article:author" content="爱肖彤真是太好了">
<meta property="article:tag" content="python">
<meta name="twitter:card" content="summary"><script src="/task/js/ui/mode.js"></script><link rel="stylesheet" href="/task/css/prism.css" type="text/css"></head><body><script defer src="https://cdn.jsdelivr.net/npm/animejs@latest/anime.min.js"></script><script defer src="/task/js/ui/fireworks.js"></script><canvas class="fireworks"></canvas><div class="container"><a class="sidebar-toggle hty-icon-button" id="menu-btn"><div class="hamburger hamburger--spin" type="button"><span class="hamburger-box"><span class="hamburger-inner"></span></span></div></a><div class="sidebar-toggle sidebar-overlay"></div><aside class="sidebar"><script src="/task/js/sidebar.js"></script><ul class="sidebar-nav"><li class="sidebar-nav-item sidebar-nav-toc hty-icon-button sidebar-nav-active" data-target="post-toc-wrap" title="文章目录"><svg class="icon" aria-hidden="true"><use xlink:href="#icon-list-ordered"></use></svg></li><li class="sidebar-nav-item sidebar-nav-overview hty-icon-button" data-target="site-overview-wrap" title="站点概览"><svg class="icon" aria-hidden="true"><use xlink:href="#icon-passport-line"></use></svg></li></ul><div class="sidebar-panel" id="site-overview-wrap"><div class="site-info fix-top"><a class="site-author-avatar" href="/task/about/" title="爱肖彤真是太好了"><img width="96" loading="lazy" src="/task/Yun.png" alt="爱肖彤真是太好了"></a><div class="site-author-name"><a href="/task/about/">爱肖彤真是太好了</a></div><a class="site-name" href="/task/about/site.html">工藤旧二の博客</a><sub class="site-subtitle"></sub><div class="site-desciption"></div></div><nav class="site-state"><a class="site-state-item hty-icon-button icon-home" href="/task/" title="首页"><span class="site-state-item-icon"><svg class="icon" aria-hidden="true"><use xlink:href="#icon-home-4-line"></use></svg></span></a><div class="site-state-item"><a href="/task/archives/" title="归档"><span class="site-state-item-icon"><svg class="icon" aria-hidden="true"><use xlink:href="#icon-archive-line"></use></svg></span><span class="site-state-item-count">57</span></a></div><div class="site-state-item"><a href="/task/categories/" title="分类"><span class="site-state-item-icon"><svg class="icon" aria-hidden="true"><use xlink:href="#icon-folder-2-line"></use></svg></span><span class="site-state-item-count">2</span></a></div><div class="site-state-item"><a href="/task/tags/" title="标签"><span class="site-state-item-icon"><svg class="icon" aria-hidden="true"><use xlink:href="#icon-price-tag-3-line"></use></svg></span><span class="site-state-item-count">50</span></a></div><a class="site-state-item hty-icon-button" target="_blank" rel="noopener" href="https://yun.yunyoujun.cn" title="文档"><span class="site-state-item-icon"><svg class="icon" aria-hidden="true"><use xlink:href="#icon-settings-line"></use></svg></span></a></nav><hr style="margin-bottom:0.5rem"><div class="links-of-author"><a class="links-of-author-item hty-icon-button" rel="noopener" title="RSS" target="_blank" style="color:orange"><svg class="icon" aria-hidden="true"><use xlink:href="#icon-rss-line"></use></svg></a><a class="links-of-author-item hty-icon-button" rel="noopener" title="QQ" target="_blank" style="color:#12B7F5"><svg class="icon" aria-hidden="true"><use xlink:href="#icon-qq-line"></use></svg></a><a class="links-of-author-item hty-icon-button" rel="noopener" title="GitHub" target="_blank" style="color:#6e5494"><svg class="icon" aria-hidden="true"><use xlink:href="#icon-github-line"></use></svg></a><a class="links-of-author-item hty-icon-button" rel="noopener" title="微博" target="_blank" style="color:#E6162D"><svg class="icon" aria-hidden="true"><use xlink:href="#icon-weibo-line"></use></svg></a><a class="links-of-author-item hty-icon-button" rel="noopener" title="豆瓣" target="_blank" style="color:#007722"><svg class="icon" aria-hidden="true"><use xlink:href="#icon-douban-line"></use></svg></a><a class="links-of-author-item hty-icon-button" rel="noopener" href="https://music.163.com/#/user/home?id=552858287" title="网易云音乐" target="_blank" style="color:#C20C0C"><svg class="icon" aria-hidden="true"><use xlink:href="#icon-netease-cloud-music-line"></use></svg></a><a class="links-of-author-item hty-icon-button" rel="noopener" title="知乎" target="_blank" style="color:#0084FF"><svg class="icon" aria-hidden="true"><use xlink:href="#icon-zhihu-line"></use></svg></a><a class="links-of-author-item hty-icon-button" rel="noopener" href="https://space.bilibili.com/15081363" title="哔哩哔哩" target="_blank" style="color:#FF8EB3"><svg class="icon" aria-hidden="true"><use xlink:href="#icon-bilibili-line"></use></svg></a><a class="links-of-author-item hty-icon-button" rel="noopener" title="Twitter" target="_blank" style="color:#1da1f2"><svg class="icon" aria-hidden="true"><use xlink:href="#icon-twitter-line"></use></svg></a><a class="links-of-author-item hty-icon-button" rel="noopener" title="Telegram Channel" target="_blank" style="color:#0088CC"><svg class="icon" aria-hidden="true"><use xlink:href="#icon-telegram-line"></use></svg></a><a class="links-of-author-item hty-icon-button" rel="noopener" title="E-Mail" target="_blank" style="color:#8E71C1"><svg class="icon" aria-hidden="true"><use xlink:href="#icon-mail-line"></use></svg></a><a class="links-of-author-item hty-icon-button" rel="noopener" title="Travelling" target="_blank" style="color:var(--hty-text-color)"><svg class="icon" aria-hidden="true"><use xlink:href="#icon-send-plane-2-line"></use></svg></a></div><hr style="margin:0.5rem 1rem"><div class="links"><a class="links-item hty-icon-button" href="/task/links/" title="我的小伙伴们" style="color:dodgerblue"><svg class="icon" aria-hidden="true"><use xlink:href="#icon-genderless-line"></use></svg></a></div><br><a class="links-item hty-icon-button" id="toggle-mode-btn" href="javascript:;" title="Mode" style="color: #f1cb64"><svg class="icon" aria-hidden="true"><use xlink:href="#icon-contrast-2-line"></use></svg></a></div><div class="sidebar-panel sidebar-panel-active" id="post-toc-wrap"><div class="post-toc"><div class="post-toc-content"><ol class="toc"><li class="toc-item toc-level-3"><a class="toc-link" href="#%E5%88%86%E5%B8%83%E5%BC%8F%E9%94%81"><span class="toc-text">分布式锁</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#%E5%8A%A0%E9%94%81%E6%93%8D%E4%BD%9C%E9%9D%9E%E5%8E%9F%E5%AD%90%E6%80%A7"><span class="toc-text">加锁操作非原子性</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E4%BD%BF%E7%94%A8setnx%E5%8E%9F%E5%AD%90%E6%80%A7%E5%8A%A0%E9%94%81"><span class="toc-text">使用setnx原子性加锁</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E8%A7%A3%E5%86%B3%E6%AD%BB%E9%94%81"><span class="toc-text">解决死锁</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E9%80%9A%E8%BF%87%E7%BA%BF%E7%A8%8B%E5%94%AF%E4%B8%80%E6%80%A7%E8%A7%A3%E5%86%B3%E8%AF%AF%E5%88%A0%E9%94%81"><span class="toc-text">通过线程唯一性解决误删锁</span></a></li></ol></li></ol></div></div></div></aside><main class="sidebar-translate" id="content"><div id="post"><article class="post-block" itemscope itemtype="https://schema.org/Article"><link itemprop="mainEntityOfPage" href="http://huang_zhao.gitee.io/task/task/2021/07/02/python/%E5%AD%A6%E4%B9%A0/%E5%88%86%E5%B8%83%E5%BC%8F%E9%94%81/"><span hidden itemprop="author" itemscope itemtype="https://schema.org/Person"><meta itemprop="name" content="爱肖彤真是太好了"><meta itemprop="description"></span><span hidden itemprop="publisher" itemscope itemtype="https://schema.org/Organization"><meta itemprop="name" content="工藤旧二の博客"></span><header class="post-header"><h1 class="post-title" itemprop="name headline">python实现分布式锁</h1><div class="post-meta"><div class="post-time" style="display:block"><span class="post-meta-item-icon"><svg class="icon" aria-hidden="true"><use xlink:href="#icon-calendar-line"></use></svg></span> <time title="创建时间：2021-07-02 13:33:43" itemprop="dateCreated datePublished" datetime="2021-07-02T13:33:43+08:00">2021-07-02</time><span class="post-meta-divider">-</span><span class="post-meta-item-icon"><svg class="icon" aria-hidden="true"><use xlink:href="#icon-calendar-2-line"></use></svg></span> <time title="修改时间：2021-07-01 14:13:58" itemprop="dateModified" datetime="2021-07-01T14:13:58+08:00">2021-07-01</time></div><span class="post-count"><span class="post-symbolcount"><span class="post-meta-item-icon" title="本文字数"><svg class="icon" aria-hidden="true"><use xlink:href="#icon-file-word-line"></use></svg></span> <span title="本文字数">2.2k</span><span class="post-meta-divider">-</span><span class="post-meta-item-icon" title="阅读时长"><svg class="icon" aria-hidden="true"><use xlink:href="#icon-timer-line"></use></svg></span> <span title="阅读时长">10m</span></span></span><span class="post-busuanzi"><span class="post-meta-divider">-</span><span class="post-meta-item-icon" title="阅读次数"><svg class="icon" aria-hidden="true"><use xlink:href="#icon-eye-line"></use></svg> <span id="busuanzi_value_page_pv"></span></span></span><div class="post-classify"><span class="post-category"><span class="post-meta-item-icon"><svg class="icon" aria-hidden="true"><use xlink:href="#icon-folder-line"></use></svg></span> <span itemprop="about" itemscope itemtype="https://schema.org/Thing"><a class="category" href="/task/categories/%E6%8A%80%E6%9C%AF%E5%88%86%E4%BA%AB/" style="--text-color:var(--hty-text-color)" itemprop="url" rel="index"><span itemprop="text">技术分享</span></a></span></span><span class="post-tag"><span class="post-meta-divider">-</span><a class="tag" href="/task/tags/python/" style="--text-color:var(--hty-text-color)"><span class="post-meta-item-icon"><svg class="icon" aria-hidden="true"><use xlink:href="#icon-price-tag-3-line"></use></svg></span><span class="tag-name">python</span></a></span></div></div></header><section class="post-body" itemprop="articleBody"><div class="post-content markdown-body" style="--smc-primary:#0078E7;"><h3 id="分布式锁"><a href="#分布式锁" class="headerlink" title="分布式锁"></a>分布式锁</h3><h4 id="加锁操作非原子性"><a href="#加锁操作非原子性" class="headerlink" title="加锁操作非原子性"></a>加锁操作非原子性</h4><pre class=" language-python"><code class="language-python"><span class="token keyword">import</span> threading<span class="token punctuation">,</span> time<span class="token punctuation">,</span> redis
<span class="token keyword">from</span> redis <span class="token keyword">import</span> StrictRedis
<span class="token comment" spellcheck="true"># 方式一：加锁操作非原子性</span>
<span class="token comment" spellcheck="true"># 失败案例</span>

<span class="token keyword">class</span> <span class="token class-name">RedisLock</span><span class="token punctuation">(</span>object<span class="token punctuation">)</span><span class="token punctuation">:</span>
    <span class="token keyword">def</span> <span class="token function">__init__</span><span class="token punctuation">(</span>self<span class="token punctuation">,</span> redis_conn<span class="token punctuation">)</span><span class="token punctuation">:</span>
        self<span class="token punctuation">.</span>redis_conn <span class="token operator">=</span> redis_conn

    <span class="token keyword">def</span> <span class="token function">get_lock_key</span><span class="token punctuation">(</span>self<span class="token punctuation">,</span> key<span class="token punctuation">)</span><span class="token punctuation">:</span>
        lock_key <span class="token operator">=</span> <span class="token string">'lock_%s'</span> <span class="token operator">%</span> key
        <span class="token keyword">return</span> lock_key

    <span class="token keyword">def</span> <span class="token function">get_lock</span><span class="token punctuation">(</span>self<span class="token punctuation">,</span> key<span class="token punctuation">)</span><span class="token punctuation">:</span>
        <span class="token triple-quoted-string string">"""
        :param key: 分布式锁key
        :return: True 表示获取到了锁
        get_lock会循环获取锁，只有得到锁的人才能退出循环

        获取锁的原理：所有需要进行a操作的线程都要先获取redis中一个规定的key，若一个线程获取key为空，则获取成功，并设置key=1，进行a操作，其他线程都会获取失败以至再次获取到key为空
        获取到key的线程进行操作a结束后，需要释放锁，就要删除key=1，以便下一个线程获取锁

        但是本方式存在漏洞：第一个线程获取到key之后，还没来得及放入key=1，就被第二个线程获取到了
        """</span>
        lock_key <span class="token operator">=</span> self<span class="token punctuation">.</span>get_lock_key<span class="token punctuation">(</span>key<span class="token punctuation">)</span>
        <span class="token keyword">while</span> <span class="token boolean">True</span><span class="token punctuation">:</span>
            value <span class="token operator">=</span> self<span class="token punctuation">.</span>redis_conn<span class="token punctuation">.</span>get<span class="token punctuation">(</span>lock_key<span class="token punctuation">)</span>
            <span class="token keyword">if</span> <span class="token operator">not</span> value<span class="token punctuation">:</span>
                self<span class="token punctuation">.</span>redis_conn<span class="token punctuation">.</span>set<span class="token punctuation">(</span>lock_key<span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">)</span>
                <span class="token keyword">return</span> <span class="token boolean">True</span>
            time<span class="token punctuation">.</span>sleep<span class="token punctuation">(</span><span class="token number">0.01</span><span class="token punctuation">)</span>

    <span class="token keyword">def</span> <span class="token function">del_lock</span><span class="token punctuation">(</span>self<span class="token punctuation">,</span> key<span class="token punctuation">)</span><span class="token punctuation">:</span>
        lock_key <span class="token operator">=</span> self<span class="token punctuation">.</span>get_lock_key<span class="token punctuation">(</span>key<span class="token punctuation">)</span>
        <span class="token keyword">return</span> self<span class="token punctuation">.</span>redis_conn<span class="token punctuation">.</span>delete<span class="token punctuation">(</span>lock_key<span class="token punctuation">)</span>

<span class="token keyword">def</span> <span class="token function">increase_data</span><span class="token punctuation">(</span>redis_conn<span class="token punctuation">,</span> lock<span class="token punctuation">,</span> key<span class="token punctuation">)</span><span class="token punctuation">:</span>
    lock_value <span class="token operator">=</span> lock<span class="token punctuation">.</span>get_lock<span class="token punctuation">(</span>key<span class="token punctuation">)</span>  <span class="token comment" spellcheck="true"># 获取锁</span>
    value <span class="token operator">=</span> redis_conn<span class="token punctuation">.</span>get<span class="token punctuation">(</span>key<span class="token punctuation">)</span>  <span class="token comment" spellcheck="true"># 获取数据</span>
    time<span class="token punctuation">.</span>sleep<span class="token punctuation">(</span><span class="token number">0.1</span><span class="token punctuation">)</span>
    <span class="token keyword">if</span> value<span class="token punctuation">:</span>
        value <span class="token operator">=</span> int<span class="token punctuation">(</span>value<span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token number">1</span>
    <span class="token keyword">else</span><span class="token punctuation">:</span>
        value <span class="token operator">=</span> <span class="token number">0</span>
    redis_conn<span class="token punctuation">.</span>set<span class="token punctuation">(</span>key<span class="token punctuation">,</span> value<span class="token punctuation">)</span>
    thread_name <span class="token operator">=</span> threading<span class="token punctuation">.</span>current_thread<span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span>name
    <span class="token keyword">print</span><span class="token punctuation">(</span>thread_name<span class="token punctuation">,</span> value<span class="token punctuation">)</span>
    lock<span class="token punctuation">.</span>del_lock<span class="token punctuation">(</span>key<span class="token punctuation">)</span>  <span class="token comment" spellcheck="true"># 释放锁</span>


<span class="token comment" spellcheck="true">##主程序</span>
<span class="token keyword">if</span> __name__ <span class="token operator">==</span> <span class="token string">"__main__"</span><span class="token punctuation">:</span>
    pool <span class="token operator">=</span> redis<span class="token punctuation">.</span>ConnectionPool<span class="token punctuation">(</span>host<span class="token operator">=</span><span class="token string">'127.0.0.1'</span><span class="token punctuation">,</span> port<span class="token operator">=</span><span class="token number">6379</span><span class="token punctuation">,</span> db<span class="token operator">=</span><span class="token number">8</span><span class="token punctuation">)</span>
    redis <span class="token operator">=</span> StrictRedis<span class="token punctuation">(</span>connection_pool<span class="token operator">=</span>pool<span class="token punctuation">)</span>
    lock <span class="token operator">=</span> RedisLock<span class="token punctuation">(</span>redis<span class="token punctuation">)</span>
    key <span class="token operator">=</span> <span class="token string">'test_key'</span>
    thread_count <span class="token operator">=</span> <span class="token number">10</span>
    redis<span class="token punctuation">.</span>delete<span class="token punctuation">(</span>key<span class="token punctuation">)</span>
    <span class="token keyword">for</span> i <span class="token keyword">in</span> range<span class="token punctuation">(</span>thread_count<span class="token punctuation">)</span><span class="token punctuation">:</span>
        <span class="token comment" spellcheck="true"># 启动10个线程调用increase_data</span>
        <span class="token comment" spellcheck="true"># 传入的lock相当于是一个锁工具，所有人都可以通过锁工具去redis中获取锁，但是锁的数量唯一</span>
        thread <span class="token operator">=</span> threading<span class="token punctuation">.</span>Thread<span class="token punctuation">(</span>target<span class="token operator">=</span>increase_data<span class="token punctuation">,</span> args<span class="token operator">=</span><span class="token punctuation">(</span>redis<span class="token punctuation">,</span> lock<span class="token punctuation">,</span> key<span class="token punctuation">)</span><span class="token punctuation">)</span>
        thread<span class="token punctuation">.</span>start<span class="token punctuation">(</span><span class="token punctuation">)</span>
    <span class="token triple-quoted-string string">"""
    实际输出结果
    Thread-1 0
    Thread-8 1
    Thread-6 Thread-7 1
    1
    Thread-9 1
    Thread-2Thread-4 2
     2Thread-3 2
    Thread-10 2

    Thread-5 2
    """</span></code></pre>
<h4 id="使用setnx原子性加锁"><a href="#使用setnx原子性加锁" class="headerlink" title="使用setnx原子性加锁"></a>使用setnx原子性加锁</h4><pre class=" language-python"><code class="language-python"><span class="token keyword">import</span> threading<span class="token punctuation">,</span> time<span class="token punctuation">,</span> redis
<span class="token keyword">from</span> redis <span class="token keyword">import</span> StrictRedis


<span class="token keyword">class</span> <span class="token class-name">RedisLock</span><span class="token punctuation">(</span>object<span class="token punctuation">)</span><span class="token punctuation">:</span>
    <span class="token keyword">def</span> <span class="token function">__init__</span><span class="token punctuation">(</span>self<span class="token punctuation">,</span> redis_conn<span class="token punctuation">)</span><span class="token punctuation">:</span>
        self<span class="token punctuation">.</span>redis_conn <span class="token operator">=</span> redis_conn

    <span class="token keyword">def</span> <span class="token function">get_lock_key</span><span class="token punctuation">(</span>self<span class="token punctuation">,</span> key<span class="token punctuation">)</span><span class="token punctuation">:</span>
        lock_key <span class="token operator">=</span> <span class="token string">'lock_%s'</span> <span class="token operator">%</span> key
        <span class="token keyword">return</span> lock_key

    <span class="token keyword">def</span> <span class="token function">get_lock</span><span class="token punctuation">(</span>self<span class="token punctuation">,</span> key<span class="token punctuation">)</span><span class="token punctuation">:</span>
        <span class="token triple-quoted-string string">"""
        :param key:
        :return:

        鉴于上面版本是由于命令不是原子性操作造成两个或多个线程同时获得锁的问题，这个版本改成使用 redis 的 setnx 命令来进行锁的查询和设置操作
            setnx 即 set if not exists，顾名思义就是当key不存在的时候才设置 value，并返回 1，如果 key 已经存在，则不进行任何操作，返回 0。

        和之前get+set的区别就是  setnx只需要一步操作即可完成获取锁和设置锁的两步操作
        这种原子性是成功的关键

        操作是成功了，但是还是有问题，若某个线程在a操作时抛出异常，那么其他所有等待获取锁的线程将陷入死循环，造成死锁
        """</span>
        lock_key <span class="token operator">=</span> self<span class="token punctuation">.</span>get_lock_key<span class="token punctuation">(</span>key<span class="token punctuation">)</span>
        <span class="token keyword">while</span> <span class="token boolean">True</span><span class="token punctuation">:</span>
            value <span class="token operator">=</span> self<span class="token punctuation">.</span>redis_conn<span class="token punctuation">.</span>setnx<span class="token punctuation">(</span>lock_key<span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">)</span>
            <span class="token keyword">if</span> value<span class="token punctuation">:</span>
                <span class="token keyword">return</span> <span class="token boolean">True</span>
            time<span class="token punctuation">.</span>sleep<span class="token punctuation">(</span><span class="token number">0.01</span><span class="token punctuation">)</span>


    <span class="token keyword">def</span> <span class="token function">del_lock</span><span class="token punctuation">(</span>self<span class="token punctuation">,</span> key<span class="token punctuation">)</span><span class="token punctuation">:</span>
        lock_key <span class="token operator">=</span> self<span class="token punctuation">.</span>get_lock_key<span class="token punctuation">(</span>key<span class="token punctuation">)</span>
        <span class="token keyword">return</span> self<span class="token punctuation">.</span>redis_conn<span class="token punctuation">.</span>delete<span class="token punctuation">(</span>lock_key<span class="token punctuation">)</span>



<span class="token keyword">def</span> <span class="token function">increase_data</span><span class="token punctuation">(</span>redis_conn<span class="token punctuation">,</span> lock<span class="token punctuation">,</span> key<span class="token punctuation">)</span><span class="token punctuation">:</span>
    lock_value <span class="token operator">=</span> lock<span class="token punctuation">.</span>get_lock<span class="token punctuation">(</span>key<span class="token punctuation">)</span>  <span class="token comment" spellcheck="true"># 获取锁</span>
    value <span class="token operator">=</span> redis_conn<span class="token punctuation">.</span>get<span class="token punctuation">(</span>key<span class="token punctuation">)</span>  <span class="token comment" spellcheck="true"># 获取数据</span>
    time<span class="token punctuation">.</span>sleep<span class="token punctuation">(</span><span class="token number">0.1</span><span class="token punctuation">)</span>
    <span class="token keyword">if</span> value<span class="token punctuation">:</span>
        value <span class="token operator">=</span> int<span class="token punctuation">(</span>value<span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token number">1</span>
    <span class="token keyword">else</span><span class="token punctuation">:</span>
        value <span class="token operator">=</span> <span class="token number">0</span>
    redis_conn<span class="token punctuation">.</span>set<span class="token punctuation">(</span>key<span class="token punctuation">,</span> value<span class="token punctuation">)</span>
    thread_name <span class="token operator">=</span> threading<span class="token punctuation">.</span>current_thread<span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span>name
    <span class="token keyword">print</span><span class="token punctuation">(</span>thread_name<span class="token punctuation">,</span> value<span class="token punctuation">)</span>
    <span class="token comment" spellcheck="true"># 模拟死锁</span>
    <span class="token comment" spellcheck="true"># if thread_name == "Thread-2":</span>
    <span class="token comment" spellcheck="true">#     print("thread-2 crash ....")</span>
    <span class="token comment" spellcheck="true">#     import sys</span>
    <span class="token comment" spellcheck="true">#     sys.exit(1)</span>
    lock<span class="token punctuation">.</span>del_lock<span class="token punctuation">(</span>key<span class="token punctuation">)</span>  <span class="token comment" spellcheck="true"># 释放锁</span>


<span class="token comment" spellcheck="true">##主程序</span>
<span class="token keyword">if</span> __name__ <span class="token operator">==</span> <span class="token string">"__main__"</span><span class="token punctuation">:</span>
    pool <span class="token operator">=</span> redis<span class="token punctuation">.</span>ConnectionPool<span class="token punctuation">(</span>host<span class="token operator">=</span><span class="token string">'127.0.0.1'</span><span class="token punctuation">,</span> port<span class="token operator">=</span><span class="token number">6379</span><span class="token punctuation">,</span> db<span class="token operator">=</span><span class="token number">8</span><span class="token punctuation">)</span>
    redis <span class="token operator">=</span> StrictRedis<span class="token punctuation">(</span>connection_pool<span class="token operator">=</span>pool<span class="token punctuation">)</span>
    lock <span class="token operator">=</span> RedisLock<span class="token punctuation">(</span>redis<span class="token punctuation">)</span>
    key <span class="token operator">=</span> <span class="token string">'test_key'</span>
    thread_count <span class="token operator">=</span> <span class="token number">10</span>
    redis<span class="token punctuation">.</span>delete<span class="token punctuation">(</span>key<span class="token punctuation">)</span>
    <span class="token keyword">for</span> i <span class="token keyword">in</span> range<span class="token punctuation">(</span>thread_count<span class="token punctuation">)</span><span class="token punctuation">:</span>
        thread <span class="token operator">=</span> threading<span class="token punctuation">.</span>Thread<span class="token punctuation">(</span>target<span class="token operator">=</span>increase_data<span class="token punctuation">,</span> args<span class="token operator">=</span><span class="token punctuation">(</span>redis<span class="token punctuation">,</span> lock<span class="token punctuation">,</span> key<span class="token punctuation">)</span><span class="token punctuation">)</span>
        thread<span class="token punctuation">.</span>start<span class="token punctuation">(</span><span class="token punctuation">)</span>

</code></pre>
<h4 id="解决死锁"><a href="#解决死锁" class="headerlink" title="解决死锁"></a>解决死锁</h4><pre class=" language-python"><code class="language-python"><span class="token keyword">import</span> threading<span class="token punctuation">,</span> time<span class="token punctuation">,</span> redis
<span class="token keyword">from</span> redis <span class="token keyword">import</span> StrictRedis


<span class="token keyword">class</span> <span class="token class-name">RedisLock</span><span class="token punctuation">(</span>object<span class="token punctuation">)</span><span class="token punctuation">:</span>
    <span class="token keyword">def</span> <span class="token function">__init__</span><span class="token punctuation">(</span>self<span class="token punctuation">,</span> redis_conn<span class="token punctuation">)</span><span class="token punctuation">:</span>
        self<span class="token punctuation">.</span>redis_conn <span class="token operator">=</span> redis_conn

    <span class="token keyword">def</span> <span class="token function">get_lock_key</span><span class="token punctuation">(</span>self<span class="token punctuation">,</span> key<span class="token punctuation">)</span><span class="token punctuation">:</span>
        lock_key <span class="token operator">=</span> <span class="token string">'lock_%s'</span> <span class="token operator">%</span> key
        <span class="token keyword">return</span> lock_key

    <span class="token keyword">def</span> <span class="token function">get_lock</span><span class="token punctuation">(</span>self<span class="token punctuation">,</span> key<span class="token punctuation">,</span> timeout<span class="token operator">=</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">:</span>
        <span class="token triple-quoted-string string">"""
        :param key:
        :param timeout:
        :return:
        根据redis的ttl机制
            扩展资料：redis的是两种失效机制
                1 被动失效：当客户端主动获取时，判断是否失效（超时）
                2 主动失效：redis中有一个定时任务，每秒执行10次，随机从设定有失效机制的key中获取20个，删除过期的key，判断下是否超过1/4的key已经失效了，如果没有执行步骤第一步再次获取20个。

        在锁之前先设定超时实现，避免死锁现象

        解决了死锁现象但是锁机制还是存在问题：线程1退出死锁后，线程2立刻获取到了锁，但是线程1还有一步删除锁的操作，就会吧线程2刚放进去的锁删掉，以至于数据混乱

        这里很容易想到flask源码中关于上下文request ctx对象唯一性的处理，通过线程id作为标识，也可以加上进程pid，机器ip，或者时间戳，就可以绝对确立唯一性了

        然后在删除锁的操作中设置设置锁和删除锁必须在同一个线程中执行


        """</span>
        lock_key <span class="token operator">=</span> self<span class="token punctuation">.</span>get_lock_key<span class="token punctuation">(</span>key<span class="token punctuation">)</span>
        <span class="token keyword">while</span> <span class="token boolean">True</span><span class="token punctuation">:</span>
            value <span class="token operator">=</span> self<span class="token punctuation">.</span>redis_conn<span class="token punctuation">.</span>set<span class="token punctuation">(</span>lock_key<span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">,</span> nx<span class="token operator">=</span><span class="token boolean">True</span><span class="token punctuation">,</span> ex<span class="token operator">=</span>timeout<span class="token punctuation">)</span>
            <span class="token keyword">if</span> value<span class="token punctuation">:</span>
                <span class="token keyword">break</span>
            time<span class="token punctuation">.</span>sleep<span class="token punctuation">(</span><span class="token number">0.1</span><span class="token punctuation">)</span>



    <span class="token keyword">def</span> <span class="token function">del_lock</span><span class="token punctuation">(</span>self<span class="token punctuation">,</span> key<span class="token punctuation">)</span><span class="token punctuation">:</span>
        lock_key <span class="token operator">=</span> self<span class="token punctuation">.</span>get_lock_key<span class="token punctuation">(</span>key<span class="token punctuation">)</span>
        <span class="token keyword">return</span> self<span class="token punctuation">.</span>redis_conn<span class="token punctuation">.</span>delete<span class="token punctuation">(</span>lock_key<span class="token punctuation">)</span>



<span class="token keyword">def</span> <span class="token function">increase_data</span><span class="token punctuation">(</span>redis_conn<span class="token punctuation">,</span> lock<span class="token punctuation">,</span> key<span class="token punctuation">)</span><span class="token punctuation">:</span>
    lock_value <span class="token operator">=</span> lock<span class="token punctuation">.</span>get_lock<span class="token punctuation">(</span>key<span class="token punctuation">)</span>  <span class="token comment" spellcheck="true"># 获取锁</span>
    value <span class="token operator">=</span> redis_conn<span class="token punctuation">.</span>get<span class="token punctuation">(</span>key<span class="token punctuation">)</span>  <span class="token comment" spellcheck="true"># 获取数据</span>
    time<span class="token punctuation">.</span>sleep<span class="token punctuation">(</span><span class="token number">2.5</span><span class="token punctuation">)</span>  <span class="token comment" spellcheck="true"># 模拟实际情况下进行的某些耗时操作, 且执行时间大于锁过期的时间</span>
    time<span class="token punctuation">.</span>sleep<span class="token punctuation">(</span><span class="token number">0.1</span><span class="token punctuation">)</span>
    <span class="token keyword">if</span> value<span class="token punctuation">:</span>
        value <span class="token operator">=</span> int<span class="token punctuation">(</span>value<span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token number">1</span>
    <span class="token keyword">else</span><span class="token punctuation">:</span>
        value <span class="token operator">=</span> <span class="token number">0</span>
    redis_conn<span class="token punctuation">.</span>set<span class="token punctuation">(</span>key<span class="token punctuation">,</span> value<span class="token punctuation">)</span>
    thread_name <span class="token operator">=</span> threading<span class="token punctuation">.</span>current_thread<span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span>name
    <span class="token keyword">print</span><span class="token punctuation">(</span>thread_name<span class="token punctuation">,</span> value<span class="token punctuation">)</span>
    <span class="token comment" spellcheck="true"># 模拟死锁</span>
    <span class="token keyword">if</span> thread_name <span class="token operator">==</span> <span class="token string">"Thread-2"</span><span class="token punctuation">:</span>
        <span class="token keyword">print</span><span class="token punctuation">(</span><span class="token string">"thread-2 crash ...."</span><span class="token punctuation">)</span>
        <span class="token keyword">import</span> sys
        sys<span class="token punctuation">.</span>exit<span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span>
    lock<span class="token punctuation">.</span>del_lock<span class="token punctuation">(</span>key<span class="token punctuation">)</span>  <span class="token comment" spellcheck="true"># 释放锁</span>


<span class="token comment" spellcheck="true">##主程序</span>
<span class="token keyword">if</span> __name__ <span class="token operator">==</span> <span class="token string">"__main__"</span><span class="token punctuation">:</span>
    pool <span class="token operator">=</span> redis<span class="token punctuation">.</span>ConnectionPool<span class="token punctuation">(</span>host<span class="token operator">=</span><span class="token string">'127.0.0.1'</span><span class="token punctuation">,</span> port<span class="token operator">=</span><span class="token number">6379</span><span class="token punctuation">,</span> db<span class="token operator">=</span><span class="token number">8</span><span class="token punctuation">)</span>
    redis <span class="token operator">=</span> StrictRedis<span class="token punctuation">(</span>connection_pool<span class="token operator">=</span>pool<span class="token punctuation">)</span>
    lock <span class="token operator">=</span> RedisLock<span class="token punctuation">(</span>redis<span class="token punctuation">)</span>
    key <span class="token operator">=</span> <span class="token string">'test_key'</span>
    thread_count <span class="token operator">=</span> <span class="token number">10</span>
    redis<span class="token punctuation">.</span>delete<span class="token punctuation">(</span>key<span class="token punctuation">)</span>
    <span class="token keyword">for</span> i <span class="token keyword">in</span> range<span class="token punctuation">(</span>thread_count<span class="token punctuation">)</span><span class="token punctuation">:</span>
        thread <span class="token operator">=</span> threading<span class="token punctuation">.</span>Thread<span class="token punctuation">(</span>target<span class="token operator">=</span>increase_data<span class="token punctuation">,</span> args<span class="token operator">=</span><span class="token punctuation">(</span>redis<span class="token punctuation">,</span> lock<span class="token punctuation">,</span> key<span class="token punctuation">)</span><span class="token punctuation">)</span>
        thread<span class="token punctuation">.</span>start<span class="token punctuation">(</span><span class="token punctuation">)</span>

</code></pre>
<h4 id="通过线程唯一性解决误删锁"><a href="#通过线程唯一性解决误删锁" class="headerlink" title="通过线程唯一性解决误删锁"></a>通过线程唯一性解决误删锁</h4><pre class=" language-python"><code class="language-python"><span class="token keyword">import</span> os
<span class="token keyword">import</span> socket
<span class="token keyword">import</span> threading<span class="token punctuation">,</span> time<span class="token punctuation">,</span> redis
<span class="token keyword">from</span> redis <span class="token keyword">import</span> StrictRedis


<span class="token keyword">class</span> <span class="token class-name">RedisLock</span><span class="token punctuation">(</span>object<span class="token punctuation">)</span><span class="token punctuation">:</span>
    <span class="token keyword">def</span> <span class="token function">__init__</span><span class="token punctuation">(</span>self<span class="token punctuation">,</span> redis_conn<span class="token punctuation">)</span><span class="token punctuation">:</span>
        self<span class="token punctuation">.</span>redis_conn <span class="token operator">=</span> redis_conn
        <span class="token comment" spellcheck="true"># 获取机器ip</span>
        self<span class="token punctuation">.</span>ip <span class="token operator">=</span> socket<span class="token punctuation">.</span>gethostbyname<span class="token punctuation">(</span>socket<span class="token punctuation">.</span>gethostname<span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
        <span class="token comment" spellcheck="true"># 获取进程pid</span>
        self<span class="token punctuation">.</span>pid <span class="token operator">=</span> os<span class="token punctuation">.</span>getpid<span class="token punctuation">(</span><span class="token punctuation">)</span>

    <span class="token keyword">def</span> <span class="token function">get_lock_key</span><span class="token punctuation">(</span>self<span class="token punctuation">,</span> key<span class="token punctuation">)</span><span class="token punctuation">:</span>
        lock_key <span class="token operator">=</span> <span class="token string">'lock_%s'</span> <span class="token operator">%</span> key
        <span class="token keyword">return</span> lock_key

    <span class="token keyword">def</span> <span class="token function">gen_unique_value</span><span class="token punctuation">(</span>self<span class="token punctuation">)</span><span class="token punctuation">:</span>
        thread_name <span class="token operator">=</span> threading<span class="token punctuation">.</span>current_thread<span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span>name
        time_now <span class="token operator">=</span> time<span class="token punctuation">.</span>time<span class="token punctuation">(</span><span class="token punctuation">)</span>
        <span class="token comment" spellcheck="true"># 机器ip 线程pid 进程名 时间戳， 确立唯一性</span>
        unique_value <span class="token operator">=</span> <span class="token string">"{0}-{1}-{2}-{3}"</span><span class="token punctuation">.</span>format<span class="token punctuation">(</span>self<span class="token punctuation">.</span>ip<span class="token punctuation">,</span> self<span class="token punctuation">.</span>pid<span class="token punctuation">,</span> thread_name<span class="token punctuation">,</span> time_now<span class="token punctuation">)</span>
        <span class="token keyword">return</span> unique_value

    <span class="token keyword">def</span> <span class="token function">get_lock</span><span class="token punctuation">(</span>self<span class="token punctuation">,</span> key<span class="token punctuation">,</span> timeout<span class="token operator">=</span><span class="token number">4</span><span class="token punctuation">)</span><span class="token punctuation">:</span>
        <span class="token triple-quoted-string string">"""
        :param key:
        :param timeout:
        :return:

        获取锁后会返回唯一标识（gen_unique_value），删除锁的时候通过判断唯一标识是否相等进行删除

        这里执行并没有成功，甚至相比之前误差更大
        原因是我们虽然解决了a线程只能删a线程放入的锁，但是当a线程判断通过后，正要进行删除key操作的时候，a线程的key过期了，此时b线程抢到了锁，并写入，然后a线程就删除了b线程写入的锁
        简单来说就是 删除操作并非原子性，中途有缝可以插 虽然这种情况可以通过给锁设置合理的超时时间来避免，比如设置一个超时时间大于线程执行时间的锁

        以上的方案中，我们是假设 redis 服务端是单集群且高可用的，忽视了以下的问题：
            如果某一时刻 redis master 节点发生了故障，集群中的某个 slave 节点变成 master 节点，
            这时候就可能出现原 master 节点上的锁没有及时同步到 slave 节点，导致其他线程同时获得锁。
            对于这个问题，可以参考 redis 官方推出的 redlock 算法，但是比较遗憾的是，该算法也没有很好地解决锁过期的问题。
        """</span>
        lock_key <span class="token operator">=</span> self<span class="token punctuation">.</span>get_lock_key<span class="token punctuation">(</span>key<span class="token punctuation">)</span>
        unique_value <span class="token operator">=</span> self<span class="token punctuation">.</span>gen_unique_value<span class="token punctuation">(</span><span class="token punctuation">)</span>
        <span class="token keyword">print</span><span class="token punctuation">(</span><span class="token string">"unique value %s"</span> <span class="token operator">%</span> unique_value<span class="token punctuation">)</span>
        <span class="token keyword">while</span> <span class="token boolean">True</span><span class="token punctuation">:</span>
            value <span class="token operator">=</span> self<span class="token punctuation">.</span>redis_conn<span class="token punctuation">.</span>set<span class="token punctuation">(</span>lock_key<span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">,</span> nx<span class="token operator">=</span><span class="token boolean">True</span><span class="token punctuation">,</span> ex<span class="token operator">=</span>timeout<span class="token punctuation">)</span>
            <span class="token keyword">if</span> value<span class="token punctuation">:</span>
                <span class="token keyword">return</span> unique_value
            <span class="token keyword">else</span><span class="token punctuation">:</span>
                thread_name <span class="token operator">=</span> threading<span class="token punctuation">.</span>current_thread<span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span>name
            time<span class="token punctuation">.</span>sleep<span class="token punctuation">(</span><span class="token number">0.1</span><span class="token punctuation">)</span>

    <span class="token keyword">def</span> <span class="token function">del_lock</span><span class="token punctuation">(</span>self<span class="token punctuation">,</span> key<span class="token punctuation">,</span> value<span class="token punctuation">)</span><span class="token punctuation">:</span>
        <span class="token triple-quoted-string string">"""
        :param key: 锁
        :param value: 进程信息
        :return:
        """</span>
        lock_key <span class="token operator">=</span> self<span class="token punctuation">.</span>get_lock_key<span class="token punctuation">(</span>key<span class="token punctuation">)</span>
        old_lock_value <span class="token operator">=</span> self<span class="token punctuation">.</span>redis_conn<span class="token punctuation">.</span>get<span class="token punctuation">(</span>lock_key<span class="token punctuation">)</span>
        <span class="token keyword">if</span> old_lock_value <span class="token operator">==</span> value<span class="token punctuation">:</span>
            <span class="token keyword">return</span> self<span class="token punctuation">.</span>redis_conn<span class="token punctuation">.</span>delete<span class="token punctuation">(</span>lock_key<span class="token punctuation">)</span>



<span class="token keyword">def</span> <span class="token function">increase_data</span><span class="token punctuation">(</span>redis_conn<span class="token punctuation">,</span> lock<span class="token punctuation">,</span> key<span class="token punctuation">)</span><span class="token punctuation">:</span>
    lock_value <span class="token operator">=</span> lock<span class="token punctuation">.</span>get_lock<span class="token punctuation">(</span>key<span class="token punctuation">)</span> <span class="token comment" spellcheck="true">#获取锁</span>
    value <span class="token operator">=</span> redis_conn<span class="token punctuation">.</span>get<span class="token punctuation">(</span>key<span class="token punctuation">)</span> <span class="token comment" spellcheck="true">#获取数据</span>
    time<span class="token punctuation">.</span>sleep<span class="token punctuation">(</span><span class="token number">2.5</span><span class="token punctuation">)</span> <span class="token comment" spellcheck="true">#模拟实际情况下进行的某些耗时操作, 且执行时间大于锁过期的时间</span>
    <span class="token keyword">if</span> value<span class="token punctuation">:</span>
        value <span class="token operator">=</span> int<span class="token punctuation">(</span>value<span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token number">1</span>
    <span class="token keyword">else</span><span class="token punctuation">:</span>
        value <span class="token operator">=</span> <span class="token number">0</span>
    redis_conn<span class="token punctuation">.</span>set<span class="token punctuation">(</span>key<span class="token punctuation">,</span> value<span class="token punctuation">)</span>
    thread_name <span class="token operator">=</span> threading<span class="token punctuation">.</span>current_thread<span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span>name
    <span class="token keyword">print</span><span class="token punctuation">(</span>thread_name<span class="token punctuation">,</span> value<span class="token punctuation">)</span>
    <span class="token keyword">if</span> thread_name <span class="token operator">==</span> <span class="token string">"Thread-2"</span><span class="token punctuation">:</span>
        <span class="token keyword">print</span><span class="token punctuation">(</span><span class="token string">"thread-2 crash ...."</span><span class="token punctuation">)</span>
        <span class="token keyword">import</span> sys
        sys<span class="token punctuation">.</span>exit<span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span>
    lock<span class="token punctuation">.</span>del_lock<span class="token punctuation">(</span>key<span class="token punctuation">,</span> lock_value<span class="token punctuation">)</span> <span class="token comment" spellcheck="true">#释放锁</span>

<span class="token comment" spellcheck="true">##主程序</span>
<span class="token keyword">if</span> __name__ <span class="token operator">==</span> <span class="token string">"__main__"</span><span class="token punctuation">:</span>
    pool <span class="token operator">=</span> redis<span class="token punctuation">.</span>ConnectionPool<span class="token punctuation">(</span>host<span class="token operator">=</span><span class="token string">'127.0.0.1'</span><span class="token punctuation">,</span> port<span class="token operator">=</span><span class="token number">6379</span><span class="token punctuation">,</span> db<span class="token operator">=</span><span class="token number">8</span><span class="token punctuation">)</span>
    redis <span class="token operator">=</span> StrictRedis<span class="token punctuation">(</span>connection_pool<span class="token operator">=</span>pool<span class="token punctuation">)</span>
    lock <span class="token operator">=</span> RedisLock<span class="token punctuation">(</span>redis<span class="token punctuation">)</span>
    key <span class="token operator">=</span> <span class="token string">'test_key'</span>
    thread_count <span class="token operator">=</span> <span class="token number">10</span>
    redis<span class="token punctuation">.</span>delete<span class="token punctuation">(</span>key<span class="token punctuation">)</span>
    <span class="token keyword">for</span> i <span class="token keyword">in</span> range<span class="token punctuation">(</span>thread_count<span class="token punctuation">)</span><span class="token punctuation">:</span>
        thread <span class="token operator">=</span> threading<span class="token punctuation">.</span>Thread<span class="token punctuation">(</span>target<span class="token operator">=</span>increase_data<span class="token punctuation">,</span> args<span class="token operator">=</span><span class="token punctuation">(</span>redis<span class="token punctuation">,</span> lock<span class="token punctuation">,</span> key<span class="token punctuation">)</span><span class="token punctuation">)</span>
        thread<span class="token punctuation">.</span>start<span class="token punctuation">(</span><span class="token punctuation">)</span>

    <span class="token triple-quoted-string string">"""
    unique value 10.0.0.13-52504-Thread-1-1621907713.510258
    unique value 10.0.0.13-52504-Thread-2-1621907713.510459
    unique value 10.0.0.13-52504-Thread-3-1621907713.510732
    unique value 10.0.0.13-52504-Thread-4-1621907713.511075
    unique value 10.0.0.13-52504-Thread-5-1621907713.511213
    unique value 10.0.0.13-52504-Thread-6-1621907713.511355
    unique value 10.0.0.13-52504-Thread-7-1621907713.511531
    unique value 10.0.0.13-52504-Thread-8-1621907713.5118861
    unique value 10.0.0.13-52504-Thread-9-1621907713.512355
    unique value 10.0.0.13-52504-Thread-10-1621907713.512751
    Thread-1 0
    Thread-6 0
    Thread-3 0
    Thread-4 1
    Thread-9 1
    Thread-7 1
    Thread-8 2
    Thread-10 2
    Thread-2 2
    thread-2 crash ....
    Thread-5 3

    """</span></code></pre>
</div><div id="reward-container"><span class="hty-icon-button button-glow" id="reward-button" title="打赏" onclick="var qr = document.getElementById(&quot;qr&quot;); qr.style.display = (qr.style.display === &quot;none&quot;) ? &quot;block&quot; : &quot;none&quot;;"><svg class="icon" aria-hidden="true"><use xlink:href="#icon-hand-coin-line"></use></svg></span><div id="reward-comment">点我就给你看点有意思的</div><div id="qr" style="display:none;"><div style="display:inline-block"><a target="_blank" rel="noopener" href="https://gitee.com/huang_zhao/hz/raw/master/hz/alipay.png"><img loading="lazy" src="https://gitee.com/huang_zhao/hz/raw/master/hz/alipay.png" alt="支付宝" title="支付宝"></a><div><span style="color:#00A3EE"><svg class="icon" aria-hidden="true"><use xlink:href="#icon-alipay-line"></use></svg></span></div></div><div style="display:inline-block"><a target="_blank" rel="noopener" href="https://gitee.com/huang_zhao/hz/raw/master/hz/qqpay.jpg"><img loading="lazy" src="https://gitee.com/huang_zhao/hz/raw/master/hz/qqpay.jpg" alt="QQ 支付" title="QQ 支付"></a><div><span style="color:#12B7F5"><svg class="icon" aria-hidden="true"><use xlink:href="#icon-qq-line"></use></svg></span></div></div><div style="display:inline-block"><a target="_blank" rel="noopener" href="https://gitee.com/huang_zhao/hz/raw/master/hz/wxpay.jpg"><img loading="lazy" src="https://gitee.com/huang_zhao/hz/raw/master/hz/wxpay.jpg" alt="微信支付" title="微信支付"></a><div><span style="color:#2DC100"><svg class="icon" aria-hidden="true"><use xlink:href="#icon-wechat-pay-line"></use></svg></span></div></div></div></div><ul class="post-copyright"><li class="post-copyright-author"><strong>本文作者：</strong>爱肖彤真是太好了</li><li class="post-copyright-link"><strong>本文链接：</strong><a href="http://huang_zhao.gitee.io/task/2021/07/02/python/%E5%AD%A6%E4%B9%A0/%E5%88%86%E5%B8%83%E5%BC%8F%E9%94%81/" title="python实现分布式锁">http://huang_zhao.gitee.io/task/2021/07/02/python/%E5%AD%A6%E4%B9%A0/%E5%88%86%E5%B8%83%E5%BC%8F%E9%94%81/</a></li><li class="post-copyright-license"><strong>版权声明：</strong>本博客所有文章除特别声明外，均默认采用 <a href="https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh" target="_blank" rel="noopener" title="CC BY-NC-SA 4.0 "><svg class="icon"><use xlink:href="#icon-creative-commons-line"></use></svg><svg class="icon"><use xlink:href="#icon-creative-commons-by-line"></use></svg><svg class="icon"><use xlink:href="#icon-creative-commons-nc-line"></use></svg><svg class="icon"><use xlink:href="#icon-creative-commons-sa-line"></use></svg></a> 许可协议。</li></ul></section></article><div class="post-nav"><div class="post-nav-item"><a class="post-nav-prev" href="/task/2021/07/07/%E6%95%B0%E6%8D%AE%E5%BA%93/redis/2021-07-07-redis%E5%BA%95%E5%B1%82%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E8%A7%A3%E6%9E%90/" rel="prev" title="redis底层数据结构解析"><svg class="icon" aria-hidden="true"><use xlink:href="#icon-arrow-left-s-line"></use></svg><span class="post-nav-text">redis底层数据结构解析</span></a></div><div class="post-nav-item"><a class="post-nav-next" href="/task/2021/07/02/python/%E6%A1%86%E6%9E%B6/fast-api/fastapi%E4%BE%9D%E8%B5%96%E6%B3%A8%E5%85%A5/" rel="next" title="fastapi依赖注入"><span class="post-nav-text">fastapi依赖注入</span><svg class="icon" aria-hidden="true"><use xlink:href="#icon-arrow-right-s-line"></use></svg></a></div></div></div></main><footer class="sidebar-translate" id="footer"><div class="copyright"><span>&copy; 2019 – 2022 </span><span class="with-love" id="animate"><svg class="icon" aria-hidden="true"><use xlink:href="#icon-cloud-line"></use></svg></span><span class="author"> 爱肖彤真是太好了</span></div><div class="powered"><span>由 <a href="https://hexo.io" target="_blank" rel="noopener">Hexo</a> 驱动 v5.1.1</span><span class="footer-separator">|</span><span>主题 - <a rel="noopener" href="https://github.com/YunYouJun/hexo-theme-yun" target="_blank"><span>Yun</span></a> v0.9.7</span></div><div class="live_time"><span>本博客已萌萌哒地运行</span><span id="display_live_time"></span><span class="moe-text">(●'◡'●)</span><script>function blog_live_time() {
  window.setTimeout(blog_live_time, 1000);
  const start = new Date('2019-04-12T00:00:00');
  const now = new Date();
  const timeDiff = (now.getTime() - start.getTime());
  const msPerMinute = 60 * 1000;
  const msPerHour = 60 * msPerMinute;
  const msPerDay = 24 * msPerHour;
  const passDay = Math.floor(timeDiff / msPerDay);
  const passHour = Math.floor((timeDiff % msPerDay) / 60 / 60 / 1000);
  const passMinute = Math.floor((timeDiff % msPerHour) / 60 / 1000);
  const passSecond = Math.floor((timeDiff % msPerMinute) / 1000);
  display_live_time.innerHTML = " " + passDay + " 天 " + passHour + " 小时 " + passMinute + " 分 " + passSecond + " 秒";
}
blog_live_time();
</script></div><div id="busuanzi"><script async src="//busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js"></script><span id="busuanzi_container_site_uv" title="总访客量"><span><svg class="icon" aria-hidden="true"><use xlink:href="#icon-user-line"></use></svg></span><span id="busuanzi_value_site_uv"></span></span><span class="footer-separator">|</span><span id="busuanzi_container_site_pv" title="总访问量"><span><svg class="icon" aria-hidden="true"><use xlink:href="#icon-eye-line"></use></svg></span><span id="busuanzi_value_site_pv"></span></span></div></footer><a class="hty-icon-button" id="goUp" aria-label="back-to-top" href="#"><svg class="icon" aria-hidden="true"><use xlink:href="#icon-arrow-up-s-line"></use></svg><svg class="progress-circle-container" viewBox="0 0 100 100"><circle class="progress-circle" id="progressCircle" cx="50" cy="50" r="48" fill="none" stroke="#0078E7" stroke-width="2" stroke-linecap="round"></circle></svg></a><a class="popup-trigger hty-icon-button icon-search" id="search" href="javascript:;" title="搜索"><span class="site-state-item-icon"><svg class="icon" aria-hidden="true"><use xlink:href="#icon-search-line"></use></svg></span></a><script>window.addEventListener("DOMContentLoaded", () => {
  // Handle and trigger popup window
  document.querySelector(".popup-trigger").addEventListener("click", () => {
    document.querySelector(".popup").classList.add("show");
    setTimeout(() => {
      document.querySelector(".search-input").focus();
    }, 100);
  });

  // Monitor main search box
  const onPopupClose = () => {
    document.querySelector(".popup").classList.remove("show");
  };

  document.querySelector(".popup-btn-close").addEventListener("click", () => {
    onPopupClose();
  });

  window.addEventListener("keyup", event => {
    if (event.key === "Escape") {
      onPopupClose();
    }
  });
});
</script><script src="/task/js/search/local-search.js" defer></script><div class="popup search-popup"><div class="search-header"><span class="popup-btn-close close-icon hty-icon-button"><svg class="icon" aria-hidden="true"><use xlink:href="#icon-close-line"></use></svg></span></div><div class="search-input-container"><input class="search-input" id="local-search-input" type="text" placeholder="搜索..." value=""></div><div id="local-search-result"></div></div></div><script defer src="/task/js/utils.js"></script><script defer src="/task/js/hexo-theme-yun.js"></script></body></html>